package org.codehaus.activemq.store.bdb;

import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.SecondaryCursor;
import com.sleepycat.je.SecondaryDatabase;
import com.sleepycat.je.SecondaryKeyCreator;
import javax.jms.JMSException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SequenceNumberCreator
  implements SecondaryKeyCreator
{
  private static final Log log = LogFactory.getLog(SequenceNumberCreator.class);

  private long counter = 1L;
  private ThreadLocal lastKeyStore = new ThreadLocal();
  private ThreadLocal deleteKeyStore = new ThreadLocal();

  public synchronized void initialise(SecondaryDatabase database) throws JMSException, DatabaseException
  {
    this.counter = queryLatestKeyInDatabase(database);
  }

  public boolean createSecondaryKey(SecondaryDatabase secondaryDatabase, DatabaseEntry keyEntry, DatabaseEntry valueEntry, DatabaseEntry resultEntry) throws DatabaseException {
    DatabaseEntry nextKey = (DatabaseEntry)this.deleteKeyStore.get();
    if (nextKey != null) {
      resultEntry.setData(nextKey.getData());
      this.deleteKeyStore.set(null);
    }
    else {
      long value = 1L;
      synchronized (this) {
        value = ++this.counter;
      }

      resultEntry.setData(BDbHelper.asBytes(value));
    }
    this.lastKeyStore.set(resultEntry);
    return true;
  }

  public DatabaseEntry getLastKey()
  {
    return (DatabaseEntry)this.lastKeyStore.get();
  }

  public void setDeleteKey(DatabaseEntry nextKey)
  {
    this.deleteKeyStore.set(nextKey);
  }

  protected long queryLatestKeyInDatabase(SecondaryDatabase database) throws JMSException, DatabaseException {
    CursorConfig cursorConfig = null;
    SecondaryCursor cursor = null;
    try {
      cursor = database.openSecondaryCursor(BDbHelper.getTransaction(), cursorConfig);
      DatabaseEntry sequenceNumberEntry = new DatabaseEntry();
      DatabaseEntry keyEntry = new DatabaseEntry();
      DatabaseEntry valueEntry = new DatabaseEntry();
      OperationStatus status = cursor.getLast(sequenceNumberEntry, keyEntry, valueEntry, LockMode.DEFAULT);
      long answer = 1L;
      if (status != OperationStatus.NOTFOUND) {
        if (status == OperationStatus.SUCCESS) {
          answer = extractLong(sequenceNumberEntry);
        }
        else {
          throw new JMSException("Invalid status code: " + status + " cannot read last sequence number");
        }
      }
      long l1;
      l1 = answer;
      return l1;
    }
    finally
    {
      
      if (cursor != null)
        try {
          cursor.close();
        }
        catch (DatabaseException e) {
          log.warn("Error closing cursor: " + e, e);
        }
    }
  }

  protected long extractLong(DatabaseEntry entry)
  {
    return BDbHelper.longFromBytes(entry.getData());
  }
}